<!DOCTYPE html>
<html>
<head>
	<!-- Global site tag (gtag.js) - Google Analytics -->
	<script async src="https://www.googletagmanager.com/gtag/js?id='UA-133422980-2"></script>
	<script>
	  window.dataLayer = window.dataLayer || [];
	  function gtag(){dataLayer.push(arguments);}
	  gtag('js', new Date());

	  gtag('config', 'UA-133422980-2');
	</script>

	<meta charset="utf-8">
	<meta http-equiv="x-ua-compatible" content="ie=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1">

	<title>
		gem5: Creating a simple cache object 
	</title>

	<!-- SITE FAVICON -->
	<link rel="shortcut icon" type="image/gif" href="/assets/img/gem5ColorVert.gif"/>

	<link rel="canonical" href="http://localhost:4000/documentation/learning_gem5/part2/simplecache/">
	<link href='https://fonts.googleapis.com/css?family=Open+Sans:400,300,700,800,600' rel='stylesheet' type='text/css'>
	<link href='https://fonts.googleapis.com/css?family=Muli:400,300' rel='stylesheet' type='text/css'>

	<!-- FAVICON -->
	<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">

	<!-- BOOTSTRAP -->
	<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">

	<!-- CUSTOM CSS -->
	<link rel="stylesheet" href="/css/main.css">
</head>


<body>
	<nav class="navbar navbar-expand-md navbar-light bg-light">
  <a class="navbar-brand" href="/">
		<img src="/assets/img/gem5ColorLong.gif" alt="gem5" height=55px>
	</a>
  <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation">
    <span class="navbar-toggler-icon"></span>
  </button>
  <div class="collapse navbar-collapse" id="navbarNavDropdown">
    <!-- LIST FOR NAVBAR -->
    <ul class="navbar-nav ml-auto">
      <!-- HOME -->
      <li class="nav-item ">
        <a class="nav-link" href="/">Home</a>
      </li>

      <!-- ABOUT -->
			<li class="nav-item dropdown ">
				<a class="nav-link dropdown-toggle" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
					About
				</a>
				<div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
          <a class="dropdown-item" href="/about">About gem5</a>
          <a class="dropdown-item" href="/publications">Publications</a>
          <a class="dropdown-item" href="/governance">Governance</a>
				</div>
			</li>

      <!-- DOCUMENTATION -->
			<li class="nav-item dropdown active">
				<a class="nav-link dropdown-toggle" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
					Documentation
				</a>
				<div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
					<!-- Pull navigation from _data/documentation.yml -->
					
            <a class="dropdown-item" href="/documentation">gem5 documentation</a>
					
            <a class="dropdown-item" href="/documentation/learning_gem5/introduction">Learning gem5</a>
					
            <a class="dropdown-item" href="http://doxygen.gem5.org/release/current/index.html">gem5 Doxygen</a>
					
            <a class="dropdown-item" href="/documentation/reporting_problems">Reporting Problems</a>
					
				</div>
			</li>

      <!-- EVENTS -->
			<li class="nav-item dropdown ">
        <a class="nav-link" href="/events/">Events</a>
			</li>

      <!-- CONTRIBUTING -->
      <li class="nav-item ">
        <a class="nav-link" href="/contributing">Contributing</a>
      </li>

      <!-- BLOG -->
      <li class="nav-item ">
        <a class="nav-link" href="/blog">Blog</a>
      </li>

      <!-- SEARCH -->
			<li class="nav-item ">
        <a class="nav-link" href="/search">Search</a>
      </li>
    </ul>
  </div>
</nav>

	<main>
		<div class="sidenav-top">
  <div class="sidenav-brand bg-light">
    <a href="/"><img src="/assets/img/gem5ColorLong.gif" height="55px"></a>
  </div>
  <div class="search">
    <form action="/search" method="get">
      <!-- <label for="search-box"><i class="fa fa-search"></i></label> -->
      <input type="text" name="query">
      <button type="submit" name="submit"><i class="fa fa-search"></i></button>
    </form>
  </div>
</div>
<div class="sidenav">
  <!-- Pull navigation from _data/documentation.yml -->
  
    
  
    
    
      <a class="item" href="/documentation/learning_gem5/introduction" role="button" aria-expanded="false" aria-controls="collapseExample">
        Introduction
      </a>
      <div class="collapse " id="introduction">
        
      </div>
    
      <a class="item" data-toggle="collapse" href="#part1" role="button" aria-expanded="false" aria-controls="collapseExample">
        Getting Started
      </a>
      <div class="collapse " id="part1">
        
          <a class="subitem " href="/documentation/learning_gem5/part1/building">Building gem5</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part1/simple_config">Creating a simple configuration script</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part1/cache_config">Adding cache to configuration script</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part1/gem5_stats">Understanding gem5 statistics and output</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part1/example_configs">Using the default configuration scripts</a>
        
      </div>
    
      <a class="item" data-toggle="collapse" href="#part2" role="button" aria-expanded="false" aria-controls="collapseExample">
        Modifying/Extending
      </a>
      <div class="collapse show" id="part2">
        
          <a class="subitem " href="/documentation/learning_gem5/part2/environment">Setting up your development environment</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part2/helloobject">Creating a very simple SimObject</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part2/debugging">Debugging gem5</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part2/events">Event-driven programming</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part2/parameters">Adding parameters to SimObjects and more events</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part2/memoryobject">Creating SimObjects in the memory system</a>
        
          <a class="subitem active" href="/documentation/learning_gem5/part2/simplecache">Creating a simple cache object</a>
        
      </div>
    
      <a class="item" data-toggle="collapse" href="#part3" role="button" aria-expanded="false" aria-controls="collapseExample">
        Modeling Cache Coherence with Ruby
      </a>
      <div class="collapse " id="part3">
        
          <a class="subitem " href="/documentation/learning_gem5/part3/MSIintro">Introduction to Ruby</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/cache-intro">MSI example cache protocol</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/cache-declarations">Declaring a state machine</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/cache-in-ports">In port code blocks</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/cache-actions">Action code blocks</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/cache-transitions">Transition code blocks</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/directory">MSI Directory implementation</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/MSIbuilding">Compiling a SLICC protocol</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/configuration">Configuring a simple Ruby system</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/running">Running the simple Ruby system</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/MSIdebugging">Debugging SLICC Protocols</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/simple-MI_example">Configuring for a standard protocol</a>
        
      </div>
    
      <a class="item" href="/documentation/learning_gem5/gem5_101/" role="button" aria-expanded="false" aria-controls="collapseExample">
        gem5 101
      </a>
      <div class="collapse " id="gem5_101">
        
      </div>
    
    
  
    
  
    
  
</div>


<div class="container" id="doc-container">
  <div class="edit"><a href="https://gem5.googlesource.com/public/gem5-website/+/refs/heads/master/README.md">Edit this page</a></div>
  <b>authors:</b> Jason Lowe-Power<br>
  

  <br>
  <h1 id="creating-a-simple-cache-object">Creating a simple cache object</h1>

<p>In this chapter, we will take the framework for a memory object we
created in the <a href="../memoryobject">last chapter</a> and add caching
logic to it.</p>

<h2 id="simplecache-simobject">SimpleCache SimObject</h2>

<p>After creating the SConscript file, that you can download
<a href="/_pages/static/scripts/part2/simplecache/SConscript">here</a>, we can create
the SimObject Python file. We will call this simple memory object
<code class="highlighter-rouge">SimpleCache</code> and create the SimObject Python file in
<code class="highlighter-rouge">src/learning_gem5/simple_cache</code>.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">m5.params</span> <span class="kn">import</span> <span class="o">*</span>
<span class="kn">from</span> <span class="nn">m5.proxy</span> <span class="kn">import</span> <span class="o">*</span>
<span class="kn">from</span> <span class="nn">MemObject</span> <span class="kn">import</span> <span class="n">MemObject</span>

<span class="k">class</span> <span class="nc">SimpleCache</span><span class="p">(</span><span class="n">MemObject</span><span class="p">):</span>
    <span class="nb">type</span> <span class="o">=</span> <span class="s">'SimpleCache'</span>
    <span class="n">cxx_header</span> <span class="o">=</span> <span class="s">"learning_gem5/simple_cache/simple_cache.hh"</span>

    <span class="n">cpu_side</span> <span class="o">=</span> <span class="n">VectorSlavePort</span><span class="p">(</span><span class="s">"CPU side port, receives requests"</span><span class="p">)</span>
    <span class="n">mem_side</span> <span class="o">=</span> <span class="n">MasterPort</span><span class="p">(</span><span class="s">"Memory side port, sends requests"</span><span class="p">)</span>

    <span class="n">latency</span> <span class="o">=</span> <span class="n">Param</span><span class="o">.</span><span class="n">Cycles</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="s">"Cycles taken on a hit or to resolve a miss"</span><span class="p">)</span>

    <span class="n">size</span> <span class="o">=</span> <span class="n">Param</span><span class="o">.</span><span class="n">MemorySize</span><span class="p">(</span><span class="s">'16kB'</span><span class="p">,</span> <span class="s">"The size of the cache"</span><span class="p">)</span>

    <span class="n">system</span> <span class="o">=</span> <span class="n">Param</span><span class="o">.</span><span class="n">System</span><span class="p">(</span><span class="n">Parent</span><span class="o">.</span><span class="nb">any</span><span class="p">,</span> <span class="s">"The system this cache is part of"</span><span class="p">)</span>
</code></pre></div></div>

<p>There are a couple of differences between this SimObject file and the
one from the <a href="../memoryobject">previous chapter</a>. First, we have a
couple of extra parameters. Namely, a latency for cache accesses and the
size of the cache. parameters-chapter goes into more detail about these
kinds of SimObject parameters.</p>

<p>Next, we include a <code class="highlighter-rouge">System</code> parameter, which is a pointer to the main
system this cache is connected to. This is needed so we can get the
cache block size from the system object when we are initializing the
cache. To reference the system object this cache is connected to, we use
a special <em>proxy parameter</em>. In this case, we use <code class="highlighter-rouge">Parent.any</code>.</p>

<p>In the Python config file, when a <code class="highlighter-rouge">SimpleCache</code> is instantiated, this
proxy parameter searches through all of the parents of the <code class="highlighter-rouge">SimpleCache</code>
instance to find a SimObject that matches the <code class="highlighter-rouge">System</code> type. Since we
often use a <code class="highlighter-rouge">System</code> as the root SimObject, you will often see a
<code class="highlighter-rouge">system</code> parameter resolved with this proxy parameter.</p>

<p>The third and final difference between the <code class="highlighter-rouge">SimpleCache</code> and the
<code class="highlighter-rouge">SimpleMemobj</code> is that instead of having two named CPU ports
(<code class="highlighter-rouge">inst_port</code> and <code class="highlighter-rouge">data_port</code>), the <code class="highlighter-rouge">SimpleCache</code> use another special
parameter: the <code class="highlighter-rouge">VectorPort</code>. <code class="highlighter-rouge">VectorPorts</code> behave similarly to regular
ports (e.g., they are resolved via <code class="highlighter-rouge">getMasterPort</code> and <code class="highlighter-rouge">getSlavePort</code>),
but they allow this object to connect to multiple peers. Then, in the
resolution functions the parameter we ignored before (<code class="highlighter-rouge">PortID idx</code>) is
used to differentiate between the different ports. By using a vector
port, this cache can be connected into the system more flexibly than the
<code class="highlighter-rouge">SimpleMemobj</code>.</p>

<h2 id="implementing-the-simplecache">Implementing the SimpleCache</h2>

<p>Most of the code for the <code class="highlighter-rouge">SimpleCache</code> is the same as the
<code class="highlighter-rouge">SimpleMemobj</code>. There are a couple of changes in the constructor and the
key memory object functions.</p>

<p>First, we need to create the CPU side ports dynamically in the
constructor and initialize the extra member functions based on the
SimObject parameters.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">SimpleCache</span><span class="o">::</span><span class="n">SimpleCache</span><span class="p">(</span><span class="n">SimpleCacheParams</span> <span class="o">*</span><span class="n">params</span><span class="p">)</span> <span class="o">:</span>
    <span class="n">MemObject</span><span class="p">(</span><span class="n">params</span><span class="p">),</span>
    <span class="n">latency</span><span class="p">(</span><span class="n">params</span><span class="o">-&gt;</span><span class="n">latency</span><span class="p">),</span>
    <span class="n">blockSize</span><span class="p">(</span><span class="n">params</span><span class="o">-&gt;</span><span class="n">system</span><span class="o">-&gt;</span><span class="n">cacheLineSize</span><span class="p">()),</span>
    <span class="n">capacity</span><span class="p">(</span><span class="n">params</span><span class="o">-&gt;</span><span class="n">size</span> <span class="o">/</span> <span class="n">blockSize</span><span class="p">),</span>
    <span class="n">memPort</span><span class="p">(</span><span class="n">params</span><span class="o">-&gt;</span><span class="n">name</span> <span class="o">+</span> <span class="s">".mem_side"</span><span class="p">,</span> <span class="k">this</span><span class="p">),</span>
    <span class="n">blocked</span><span class="p">(</span><span class="nb">false</span><span class="p">),</span> <span class="n">outstandingPacket</span><span class="p">(</span><span class="nb">nullptr</span><span class="p">),</span> <span class="n">waitingPortId</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">params</span><span class="o">-&gt;</span><span class="n">port_cpu_side_connection_count</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">cpuPorts</span><span class="p">.</span><span class="n">emplace_back</span><span class="p">(</span><span class="n">name</span><span class="p">()</span> <span class="o">+</span> <span class="n">csprintf</span><span class="p">(</span><span class="s">".cpu_side[%d]"</span><span class="p">,</span> <span class="n">i</span><span class="p">),</span> <span class="n">i</span><span class="p">,</span> <span class="k">this</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>In this function, we use the <code class="highlighter-rouge">cacheLineSize</code> from the system parameters
to set the <code class="highlighter-rouge">blockSize</code> for this cache. We also initialize the capacity
based on the block size and the parameter and initialize other member
variables we will need below. Finally, we must create a number of
<code class="highlighter-rouge">CPUSidePorts</code> based on the number of connections to this object. Since
the <code class="highlighter-rouge">cpu_side</code> port was declared as a <code class="highlighter-rouge">VectorSlavePort</code> in the SimObject
Python file, the parameter automatically has a variable
<code class="highlighter-rouge">port_cpu_side_connection_count</code>. This is based on the Python name of
the parameter. For each of these connections we add a new <code class="highlighter-rouge">CPUSidePort</code>
to a <code class="highlighter-rouge">cpuPorts</code> vector declared in the <code class="highlighter-rouge">SimpleCache</code> class.</p>

<p>We also add one extra member variable to the <code class="highlighter-rouge">CPUSidePort</code> to save its
id, and we add this as a parameter to its constructor.</p>

<p>Next, we need to implement <code class="highlighter-rouge">getMasterPort</code> and <code class="highlighter-rouge">getSlavePort</code>. The
<code class="highlighter-rouge">getMasterPort</code> is exactly the same as the <code class="highlighter-rouge">SimpleMemobj</code>. For
<code class="highlighter-rouge">getSlavePort</code>, we now need to return the port based on the id
requested.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">BaseSlavePort</span><span class="o">&amp;</span>
<span class="n">SimpleCache</span><span class="o">::</span><span class="n">getSlavePort</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&amp;</span> <span class="n">if_name</span><span class="p">,</span> <span class="n">PortID</span> <span class="n">idx</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">if_name</span> <span class="o">==</span> <span class="s">"cpu_side"</span> <span class="o">&amp;&amp;</span> <span class="n">idx</span> <span class="o">&lt;</span> <span class="n">cpuPorts</span><span class="p">.</span><span class="n">size</span><span class="p">())</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">cpuPorts</span><span class="p">[</span><span class="n">idx</span><span class="p">];</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">MemObject</span><span class="o">::</span><span class="n">getSlavePort</span><span class="p">(</span><span class="n">if_name</span><span class="p">,</span> <span class="n">idx</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The implementation of the <code class="highlighter-rouge">CPUSidePort</code> and the <code class="highlighter-rouge">MemSidePort</code> is almost
the same as in the <code class="highlighter-rouge">SimpleMemobj</code>. The only difference is we need to add
an extra parameter to <code class="highlighter-rouge">handleRequest</code> that is the id of the port which
the request originated. Without this id, we would not be able to forward
the response to the correct port. The <code class="highlighter-rouge">SimpleMemobj</code> knew which port to
send replies based on whether the original request was an instruction or
data accesses. However, this information is not useful to the
<code class="highlighter-rouge">SimpleCache</code> since it uses a vector of ports and not named ports.</p>

<p>The new <code class="highlighter-rouge">handleRequest</code> function does two different things than the
<code class="highlighter-rouge">handleRequest</code> function in the <code class="highlighter-rouge">SimpleMemobj</code>. First, it stores the
port id of the request as discussed above. Since the <code class="highlighter-rouge">SimpleCache</code> is
blocking and only allows a single request outstanding at a time, we only
need to save a single port id.</p>

<p>Second, it takes time to access a cache. Therefore, we need to take into
account the latency to access the cache tags and the cache data for a
request. We added an extra parameter to the cache object for this, and
in <code class="highlighter-rouge">handleRequest</code> we now use an event to stall the request for the
needed amount of time. We schedule a new event for <code class="highlighter-rouge">latency</code> cycles in
the future. The <code class="highlighter-rouge">clockEdge</code> function returns the <em>tick</em> that the <em>nth</em>
cycle in the future occurs on.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">bool</span>
<span class="n">SimpleCache</span><span class="o">::</span><span class="n">handleRequest</span><span class="p">(</span><span class="n">PacketPtr</span> <span class="n">pkt</span><span class="p">,</span> <span class="kt">int</span> <span class="n">port_id</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">blocked</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">return</span> <span class="nb">false</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="n">DPRINTF</span><span class="p">(</span><span class="n">SimpleCache</span><span class="p">,</span> <span class="s">"Got request for addr %#x</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">pkt</span><span class="o">-&gt;</span><span class="n">getAddr</span><span class="p">());</span>

    <span class="n">blocked</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
    <span class="n">waitingPortId</span> <span class="o">=</span> <span class="n">port_id</span><span class="p">;</span>

    <span class="n">schedule</span><span class="p">(</span><span class="k">new</span> <span class="n">AccessEvent</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="n">pkt</span><span class="p">),</span> <span class="n">clockEdge</span><span class="p">(</span><span class="n">latency</span><span class="p">));</span>

    <span class="k">return</span> <span class="nb">true</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The <code class="highlighter-rouge">AccessEvent</code> is a little more complicated than the <code class="highlighter-rouge">EventWrapper</code>
we used in events-chapter. Instead of using an <code class="highlighter-rouge">EventWrapper</code>, in the
<code class="highlighter-rouge">SimpleCache</code> we will use a new class. The reason we cannot use an
<code class="highlighter-rouge">EventWrapper</code>, is that we need to pass the packet (<code class="highlighter-rouge">pkt</code>) from
<code class="highlighter-rouge">handleRequest</code> to the event handler function. The following code is the
<code class="highlighter-rouge">AccessEvent</code> class. We only need to implement the <code class="highlighter-rouge">process</code> function,
that calls the function we want to use as our event handler, in this
case <code class="highlighter-rouge">accessTming</code>. We also pass the flag <code class="highlighter-rouge">AutoDelete</code> to the event
constructor so we do not need to worry about freeing the memory for the
dynamically created object. The event code will automatically delete the
object after the <code class="highlighter-rouge">process</code> function has executed.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">AccessEvent</span> <span class="o">:</span> <span class="k">public</span> <span class="n">Event</span>
<span class="p">{</span>
  <span class="nl">private:</span>
    <span class="n">SimpleCache</span> <span class="o">*</span><span class="n">cache</span><span class="p">;</span>
    <span class="n">PacketPtr</span> <span class="n">pkt</span><span class="p">;</span>
  <span class="nl">public:</span>
    <span class="n">AccessEvent</span><span class="p">(</span><span class="n">SimpleCache</span> <span class="o">*</span><span class="n">cache</span><span class="p">,</span> <span class="n">PacketPtr</span> <span class="n">pkt</span><span class="p">)</span> <span class="o">:</span>
        <span class="n">Event</span><span class="p">(</span><span class="n">Default_Pri</span><span class="p">,</span> <span class="n">AutoDelete</span><span class="p">),</span> <span class="n">cache</span><span class="p">(</span><span class="n">cache</span><span class="p">),</span> <span class="n">pkt</span><span class="p">(</span><span class="n">pkt</span><span class="p">)</span>
    <span class="p">{</span> <span class="p">}</span>
    <span class="kt">void</span> <span class="n">process</span><span class="p">()</span> <span class="k">override</span> <span class="p">{</span>
        <span class="n">cache</span><span class="o">-&gt;</span><span class="n">accessTiming</span><span class="p">(</span><span class="n">pkt</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">};</span>
</code></pre></div></div>

<p>Now, we need to implement the event handler, <code class="highlighter-rouge">accessTiming</code>.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span>
<span class="n">SimpleCache</span><span class="o">::</span><span class="n">accessTiming</span><span class="p">(</span><span class="n">PacketPtr</span> <span class="n">pkt</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">bool</span> <span class="n">hit</span> <span class="o">=</span> <span class="n">accessFunctional</span><span class="p">(</span><span class="n">pkt</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">hit</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">pkt</span><span class="o">-&gt;</span><span class="n">makeResponse</span><span class="p">();</span>
        <span class="n">sendResponse</span><span class="p">(</span><span class="n">pkt</span><span class="p">);</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
        <span class="o">&lt;</span><span class="n">miss</span> <span class="n">handling</span><span class="o">&gt;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>This function first <em>functionally</em> accesses the cache. This function
<code class="highlighter-rouge">accessFunctional</code> (described below) performs the functional access of
the cache and either reads or writes the cache on a hit or returns that
the access was a miss.</p>

<p>If the access is a hit, we simply need to respond to the packet. To
respond, you first must call the function <code class="highlighter-rouge">makeResponse</code> on the packet.
This converts the packet from a request packet to a response packet. For
instance, if the memory command in the packet was a <code class="highlighter-rouge">ReadReq</code> this gets
converted into a <code class="highlighter-rouge">ReadResp</code>. Writes behave similarly. Then, we can send
the response back to the CPU.</p>

<p>The <code class="highlighter-rouge">sendResponse</code> function does the same things as the <code class="highlighter-rouge">handleResponse</code>
function in the <code class="highlighter-rouge">SimpleMemobj</code> except that it uses the <code class="highlighter-rouge">waitingPortId</code>
to send the packet to the right port. In this function, we need to mark
the <code class="highlighter-rouge">SimpleCache</code> unblocked before calling <code class="highlighter-rouge">sendPacket</code> in case the peer
on the CPU side immediately calls <code class="highlighter-rouge">sendTimingReq</code>. Then, we try to send
retries to the CPU side ports if the <code class="highlighter-rouge">SimpleCache</code> can now receive
requests and the ports need to be sent retries.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="n">SimpleCache</span><span class="o">::</span><span class="n">sendResponse</span><span class="p">(</span><span class="n">PacketPtr</span> <span class="n">pkt</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">int</span> <span class="n">port</span> <span class="o">=</span> <span class="n">waitingPortId</span><span class="p">;</span>

    <span class="n">blocked</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
    <span class="n">waitingPortId</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>

    <span class="n">cpuPorts</span><span class="p">[</span><span class="n">port</span><span class="p">].</span><span class="n">sendPacket</span><span class="p">(</span><span class="n">pkt</span><span class="p">);</span>
    <span class="k">for</span> <span class="p">(</span><span class="k">auto</span><span class="o">&amp;</span> <span class="n">port</span> <span class="o">:</span> <span class="n">cpuPorts</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">port</span><span class="p">.</span><span class="n">trySendRetry</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<hr />

<p>Back to the <code class="highlighter-rouge">accessTiming</code> function, we now need to handle the cache
miss case. On a miss, we first have to check to see if the missing
packet is to an entire cache block. If the packet is aligned and the
size of the request is the size of a cache block, then we can simply
forward the request to memory, just like in the <code class="highlighter-rouge">SimpleMemobj</code>.</p>

<p>However, if the packet is smaller than a cache block, then we need to
create a new packet to read the entire cache block from memory. Here,
whether the packet is a read or a write request, we send a read request
to memory to load the data for the cache block into the cache. In the
case of a write, it will occur in the cache after we have loaded the
data from memory.</p>

<p>Then, we create a new packet, that is <code class="highlighter-rouge">blockSize</code> in size and we call
the <code class="highlighter-rouge">allocate</code> function to allocate memory in the <code class="highlighter-rouge">Packet</code> object for
the data that we will read from memory. Note: this memory is freed when
we free the packet. We use the original request object in the packet so
the memory-side objects know the original requestor and the original
request type for statistics.</p>

<p>Finally, we save the original packet pointer (<code class="highlighter-rouge">pkt</code>) in a member
variable <code class="highlighter-rouge">outstandingPacket</code> so we can recover it when the <code class="highlighter-rouge">SimpleCache</code>
receives a response. Then, we send the new packet across the memory side
port.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span>
<span class="n">SimpleCache</span><span class="o">::</span><span class="n">accessTiming</span><span class="p">(</span><span class="n">PacketPtr</span> <span class="n">pkt</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">bool</span> <span class="n">hit</span> <span class="o">=</span> <span class="n">accessFunctional</span><span class="p">(</span><span class="n">pkt</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">hit</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">pkt</span><span class="o">-&gt;</span><span class="n">makeResponse</span><span class="p">();</span>
        <span class="n">sendResponse</span><span class="p">(</span><span class="n">pkt</span><span class="p">);</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
        <span class="n">Addr</span> <span class="n">addr</span> <span class="o">=</span> <span class="n">pkt</span><span class="o">-&gt;</span><span class="n">getAddr</span><span class="p">();</span>
        <span class="n">Addr</span> <span class="n">block_addr</span> <span class="o">=</span> <span class="n">pkt</span><span class="o">-&gt;</span><span class="n">getBlockAddr</span><span class="p">(</span><span class="n">blockSize</span><span class="p">);</span>
        <span class="kt">unsigned</span> <span class="n">size</span> <span class="o">=</span> <span class="n">pkt</span><span class="o">-&gt;</span><span class="n">getSize</span><span class="p">();</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">addr</span> <span class="o">==</span> <span class="n">block_addr</span> <span class="o">&amp;&amp;</span> <span class="n">size</span> <span class="o">==</span> <span class="n">blockSize</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">DPRINTF</span><span class="p">(</span><span class="n">SimpleCache</span><span class="p">,</span> <span class="s">"forwarding packet</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
            <span class="n">memPort</span><span class="p">.</span><span class="n">sendPacket</span><span class="p">(</span><span class="n">pkt</span><span class="p">);</span>
        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
            <span class="n">DPRINTF</span><span class="p">(</span><span class="n">SimpleCache</span><span class="p">,</span> <span class="s">"Upgrading packet to block size</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
            <span class="n">panic_if</span><span class="p">(</span><span class="n">addr</span> <span class="o">-</span> <span class="n">block_addr</span> <span class="o">+</span> <span class="n">size</span> <span class="o">&gt;</span> <span class="n">blockSize</span><span class="p">,</span>
                     <span class="s">"Cannot handle accesses that span multiple cache lines"</span><span class="p">);</span>

            <span class="n">assert</span><span class="p">(</span><span class="n">pkt</span><span class="o">-&gt;</span><span class="n">needsResponse</span><span class="p">());</span>
            <span class="n">MemCmd</span> <span class="n">cmd</span><span class="p">;</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">pkt</span><span class="o">-&gt;</span><span class="n">isWrite</span><span class="p">()</span> <span class="o">||</span> <span class="n">pkt</span><span class="o">-&gt;</span><span class="n">isRead</span><span class="p">())</span> <span class="p">{</span>
                <span class="n">cmd</span> <span class="o">=</span> <span class="n">MemCmd</span><span class="o">::</span><span class="n">ReadReq</span><span class="p">;</span>
            <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
                <span class="n">panic</span><span class="p">(</span><span class="s">"Unknown packet type in upgrade size"</span><span class="p">);</span>
            <span class="p">}</span>

            <span class="n">PacketPtr</span> <span class="n">new_pkt</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Packet</span><span class="p">(</span><span class="n">pkt</span><span class="o">-&gt;</span><span class="n">req</span><span class="p">,</span> <span class="n">cmd</span><span class="p">,</span> <span class="n">blockSize</span><span class="p">);</span>
            <span class="n">new_pkt</span><span class="o">-&gt;</span><span class="n">allocate</span><span class="p">();</span>

            <span class="n">outstandingPacket</span> <span class="o">=</span> <span class="n">pkt</span><span class="p">;</span>

            <span class="n">memPort</span><span class="p">.</span><span class="n">sendPacket</span><span class="p">(</span><span class="n">new_pkt</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>On a response from memory, we know that this was caused by a cache miss.
The first step is to insert the responding packet into the cache.</p>

<p>Then, either there is an <code class="highlighter-rouge">outstandingPacket</code>, in which case we need to
forward that packet to the original requestor, or there is no
<code class="highlighter-rouge">outstandingPacket</code> which means we should forward the <code class="highlighter-rouge">pkt</code> in the
response to the original requestor.</p>

<p>If the packet we are receiving as a response was an upgrade packet
because the original request was smaller than a cache line, then we need
to copy the new data to the outstandingPacket packet or write to the
cache on a write. Then, we need to delete the new packet that we made in
the miss handling logic.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">bool</span>
<span class="n">SimpleCache</span><span class="o">::</span><span class="n">handleResponse</span><span class="p">(</span><span class="n">PacketPtr</span> <span class="n">pkt</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">assert</span><span class="p">(</span><span class="n">blocked</span><span class="p">);</span>
    <span class="n">DPRINTF</span><span class="p">(</span><span class="n">SimpleCache</span><span class="p">,</span> <span class="s">"Got response for addr %#x</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">pkt</span><span class="o">-&gt;</span><span class="n">getAddr</span><span class="p">());</span>
    <span class="n">insert</span><span class="p">(</span><span class="n">pkt</span><span class="p">);</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">outstandingPacket</span> <span class="o">!=</span> <span class="nb">nullptr</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">accessFunctional</span><span class="p">(</span><span class="n">outstandingPacket</span><span class="p">);</span>
        <span class="n">outstandingPacket</span><span class="o">-&gt;</span><span class="n">makeResponse</span><span class="p">();</span>
        <span class="k">delete</span> <span class="n">pkt</span><span class="p">;</span>
        <span class="n">pkt</span> <span class="o">=</span> <span class="n">outstandingPacket</span><span class="p">;</span>
        <span class="n">outstandingPacket</span> <span class="o">=</span> <span class="nb">nullptr</span><span class="p">;</span>
    <span class="p">}</span> <span class="c1">// else, pkt contains the data it needs</span>

    <span class="n">sendResponse</span><span class="p">(</span><span class="n">pkt</span><span class="p">);</span>

    <span class="k">return</span> <span class="nb">true</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="functional-cache-logic">Functional cache logic</h3>

<p>Now, we need to implement two more functions: <code class="highlighter-rouge">accessFunctional</code> and
<code class="highlighter-rouge">insert</code>. These two functions make up the key components of the cache
logic.</p>

<p>First, to functionally update the cache, we first need storage for the
cache contents. The simplest possible cache storage is a map (hashtable)
that maps from addresses to data. Thus, we will add the following member
to the <code class="highlighter-rouge">SimpleCache</code>.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">std</span><span class="o">::</span><span class="n">unordered_map</span><span class="o">&lt;</span><span class="n">Addr</span><span class="p">,</span> <span class="kt">uint8_t</span><span class="o">*&gt;</span> <span class="n">cacheStore</span><span class="p">;</span>
</code></pre></div></div>

<p>To access the cache, we first check to see if there is an entry in the
map which matches the address in the packet. We use the <code class="highlighter-rouge">getBlockAddr</code>
function of the <code class="highlighter-rouge">Packet</code> type to get the block-aligned address. Then, we
simply search for that address in the map. If we do not find the
address, then this function returns <code class="highlighter-rouge">false</code>, the data is not in the
cache, and it is a miss.</p>

<p>Otherwise, if the packet is a write request, we need to update the data
in the cache. To do this, we write the data from the packet to the
cache. We use the <code class="highlighter-rouge">writeDataToBlock</code> function which writes the data in
the packet to the write offset into a potentially larger block of data.
This function takes the cache block offset and the block size (as a
parameter) and writes the correct offset into the pointer passed as the
first parameter.</p>

<p>If the packet is a read request, we need to update the packet’s data
with the data from the cache. The <code class="highlighter-rouge">setDataFromBlock</code> function performs
the same offset calculation as the <code class="highlighter-rouge">writeDataToBlock</code> function, but
writes the packet with the data from the pointer in the first parameter.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">bool</span>
<span class="n">SimpleCache</span><span class="o">::</span><span class="n">accessFunctional</span><span class="p">(</span><span class="n">PacketPtr</span> <span class="n">pkt</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">Addr</span> <span class="n">block_addr</span> <span class="o">=</span> <span class="n">pkt</span><span class="o">-&gt;</span><span class="n">getBlockAddr</span><span class="p">(</span><span class="n">blockSize</span><span class="p">);</span>
    <span class="k">auto</span> <span class="n">it</span> <span class="o">=</span> <span class="n">cacheStore</span><span class="p">.</span><span class="n">find</span><span class="p">(</span><span class="n">block_addr</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">it</span> <span class="o">!=</span> <span class="n">cacheStore</span><span class="p">.</span><span class="n">end</span><span class="p">())</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">pkt</span><span class="o">-&gt;</span><span class="n">isWrite</span><span class="p">())</span> <span class="p">{</span>
            <span class="n">pkt</span><span class="o">-&gt;</span><span class="n">writeDataToBlock</span><span class="p">(</span><span class="n">it</span><span class="o">-&gt;</span><span class="n">second</span><span class="p">,</span> <span class="n">blockSize</span><span class="p">);</span>
        <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">pkt</span><span class="o">-&gt;</span><span class="n">isRead</span><span class="p">())</span> <span class="p">{</span>
            <span class="n">pkt</span><span class="o">-&gt;</span><span class="n">setDataFromBlock</span><span class="p">(</span><span class="n">it</span><span class="o">-&gt;</span><span class="n">second</span><span class="p">,</span> <span class="n">blockSize</span><span class="p">);</span>
        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
            <span class="n">panic</span><span class="p">(</span><span class="s">"Unknown packet type!"</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="k">return</span> <span class="nb">true</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="nb">false</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Finally, we also need to implement the <code class="highlighter-rouge">insert</code> function. This function
is called every time the memory side port responds to a request.</p>

<p>The first step is to check if the cache is currently full. If the cache
has more entries (blocks) than the capacity of the cache as set by the
SimObject parameter, then we need to evict something. The following code
evicts a random entry by leveraging the hashtable implementation of the
C++ <code class="highlighter-rouge">unordered_map</code>.</p>

<p>On an eviction, we need to write the data back to the backing memory in
case it has been updated. For this, we create a new <code class="highlighter-rouge">Request</code>-<code class="highlighter-rouge">Packet</code>
pair. The packet uses a new memory command: <code class="highlighter-rouge">MemCmd::WritebackDirty</code>.
Then, we send the packet across the memory side port (<code class="highlighter-rouge">memPort</code>) and
erase the entry in the cache storage map.</p>

<p>Then, after a block has potentially been evicted, we add the new address
to the cache. For this we simply allocate space for the block and add an
entry to the map. Finally, we write the data from the response packet in
to the newly allocated block. This data is guaranteed to be the size of
the cache block since we made sure to make a new packet in the cache
miss logic if the packet was smaller than a cache block.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span>
<span class="n">SimpleCache</span><span class="o">::</span><span class="n">insert</span><span class="p">(</span><span class="n">PacketPtr</span> <span class="n">pkt</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">cacheStore</span><span class="p">.</span><span class="n">size</span><span class="p">()</span> <span class="o">&gt;=</span> <span class="n">capacity</span><span class="p">)</span> <span class="p">{</span>
        <span class="c1">// Select random thing to evict. This is a little convoluted since we</span>
        <span class="c1">// are using a std::unordered_map. See http://bit.ly/2hrnLP2</span>
        <span class="kt">int</span> <span class="n">bucket</span><span class="p">,</span> <span class="n">bucket_size</span><span class="p">;</span>
        <span class="k">do</span> <span class="p">{</span>
            <span class="n">bucket</span> <span class="o">=</span> <span class="n">random_mt</span><span class="p">.</span><span class="n">random</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">cacheStore</span><span class="p">.</span><span class="n">bucket_count</span><span class="p">()</span> <span class="o">-</span> <span class="mi">1</span><span class="p">);</span>
        <span class="p">}</span> <span class="k">while</span> <span class="p">(</span> <span class="p">(</span><span class="n">bucket_size</span> <span class="o">=</span> <span class="n">cacheStore</span><span class="p">.</span><span class="n">bucket_size</span><span class="p">(</span><span class="n">bucket</span><span class="p">))</span> <span class="o">==</span> <span class="mi">0</span> <span class="p">);</span>
        <span class="k">auto</span> <span class="n">block</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">next</span><span class="p">(</span><span class="n">cacheStore</span><span class="p">.</span><span class="n">begin</span><span class="p">(</span><span class="n">bucket</span><span class="p">),</span>
                               <span class="n">random_mt</span><span class="p">.</span><span class="n">random</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">bucket_size</span> <span class="o">-</span> <span class="mi">1</span><span class="p">));</span>

        <span class="n">RequestPtr</span> <span class="n">req</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Request</span><span class="p">(</span><span class="n">block</span><span class="o">-&gt;</span><span class="n">first</span><span class="p">,</span> <span class="n">blockSize</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
        <span class="n">PacketPtr</span> <span class="n">new_pkt</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Packet</span><span class="p">(</span><span class="n">req</span><span class="p">,</span> <span class="n">MemCmd</span><span class="o">::</span><span class="n">WritebackDirty</span><span class="p">,</span> <span class="n">blockSize</span><span class="p">);</span>
        <span class="n">new_pkt</span><span class="o">-&gt;</span><span class="n">dataDynamic</span><span class="p">(</span><span class="n">block</span><span class="o">-&gt;</span><span class="n">second</span><span class="p">);</span> <span class="c1">// This will be deleted later</span>

        <span class="n">DPRINTF</span><span class="p">(</span><span class="n">SimpleCache</span><span class="p">,</span> <span class="s">"Writing packet back %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">pkt</span><span class="o">-&gt;</span><span class="n">print</span><span class="p">());</span>
        <span class="n">memPort</span><span class="p">.</span><span class="n">sendTimingReq</span><span class="p">(</span><span class="n">new_pkt</span><span class="p">);</span>

        <span class="n">cacheStore</span><span class="p">.</span><span class="n">erase</span><span class="p">(</span><span class="n">block</span><span class="o">-&gt;</span><span class="n">first</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="kt">uint8_t</span> <span class="o">*</span><span class="n">data</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">uint8_t</span><span class="p">[</span><span class="n">blockSize</span><span class="p">];</span>
    <span class="n">cacheStore</span><span class="p">[</span><span class="n">pkt</span><span class="o">-&gt;</span><span class="n">getAddr</span><span class="p">()]</span> <span class="o">=</span> <span class="n">data</span><span class="p">;</span>

    <span class="n">pkt</span><span class="o">-&gt;</span><span class="n">writeDataToBlock</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">blockSize</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="creating-a-config-file-for-the-cache">Creating a config file for the cache</h2>

<p>The last step in our implementation is to create a new Python config
script that uses our cache. We can use the outline from the
<a href="../memoryobject">last chapter</a> as a starting point. The only
difference is we may want to set the parameters of this cache (e.g., set
the size of the cache to <code class="highlighter-rouge">1kB</code>) and instead of using the named ports
(<code class="highlighter-rouge">data_port</code> and <code class="highlighter-rouge">inst_port</code>), we just use the <code class="highlighter-rouge">cpu_side</code> port twice.
Since <code class="highlighter-rouge">cpu_side</code> is a <code class="highlighter-rouge">VectorPort</code>, it will automatically create
multiple port connections.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">m5</span>
<span class="kn">from</span> <span class="nn">m5.objects</span> <span class="kn">import</span> <span class="o">*</span>

<span class="o">...</span>

<span class="n">system</span><span class="o">.</span><span class="n">cache</span> <span class="o">=</span> <span class="n">SimpleCache</span><span class="p">(</span><span class="n">size</span><span class="o">=</span><span class="s">'1kB'</span><span class="p">)</span>

<span class="n">system</span><span class="o">.</span><span class="n">cpu</span><span class="o">.</span><span class="n">icache_port</span> <span class="o">=</span> <span class="n">system</span><span class="o">.</span><span class="n">cache</span><span class="o">.</span><span class="n">cpu_side</span>
<span class="n">system</span><span class="o">.</span><span class="n">cpu</span><span class="o">.</span><span class="n">dcache_port</span> <span class="o">=</span> <span class="n">system</span><span class="o">.</span><span class="n">cache</span><span class="o">.</span><span class="n">cpu_side</span>

<span class="n">system</span><span class="o">.</span><span class="n">membus</span> <span class="o">=</span> <span class="n">SystemXBar</span><span class="p">()</span>

<span class="n">system</span><span class="o">.</span><span class="n">cache</span><span class="o">.</span><span class="n">mem_side</span> <span class="o">=</span> <span class="n">system</span><span class="o">.</span><span class="n">membus</span><span class="o">.</span><span class="n">slave</span>

<span class="o">...</span>
</code></pre></div></div>

<p>The Python config file can be downloaded
<a href="/_pages/static/scripts/part2/simplecache/simple_cache.py">here</a>.</p>

<p>Running this script should produce the expected output from the hello
binary.</p>

<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gem5 Simulator System.  http://gem5.org
gem5 is copyrighted software; use the --copyright option for details.

gem5 compiled Jan 10 2017 17:38:15
gem5 started Jan 10 2017 17:40:03
gem5 executing on chinook, pid 29031
command line: build/X86/gem5.opt configs/learning_gem5/part2/simple_cache.py

Global frequency set at 1000000000000 ticks per second
warn: DRAM device capacity (8192 Mbytes) does not match the address range assigned (512 Mbytes)
0: system.remote_gdb.listener: listening for remote gdb #0 on port 7000
warn: CoherentXBar system.membus has no snooping ports attached!
warn: ClockedObject: More than one power state change request encountered within the same simulation tick
Beginning simulation!
info: Entering event queue @ 0.  Starting simulation...
Hello world!
Exiting @ tick 56082000 because target called exit()
</code></pre></div></div>

<p>Modifying the size of the cache, for instance to 128 KB, should improve
the performance of the system.</p>

<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gem5 Simulator System.  http://gem5.org
gem5 is copyrighted software; use the --copyright option for details.

gem5 compiled Jan 10 2017 17:38:15
gem5 started Jan 10 2017 17:41:10
gem5 executing on chinook, pid 29037
command line: build/X86/gem5.opt configs/learning_gem5/part2/simple_cache.py

Global frequency set at 1000000000000 ticks per second
warn: DRAM device capacity (8192 Mbytes) does not match the address range assigned (512 Mbytes)
0: system.remote_gdb.listener: listening for remote gdb #0 on port 7000
warn: CoherentXBar system.membus has no snooping ports attached!
warn: ClockedObject: More than one power state change request encountered within the same simulation tick
Beginning simulation!
info: Entering event queue @ 0.  Starting simulation...
Hello world!
Exiting @ tick 32685000 because target called exit()
</code></pre></div></div>

<h2 id="adding-statistics-to-the-cache">Adding statistics to the cache</h2>

<p>Knowing the overall execution time of the system is one important
metric. However, you may want to include other statistics as well, such
as the hit and miss rates of the cache. To do this, we need to add some
statistics to the <code class="highlighter-rouge">SimpleCache</code> object.</p>

<p>First, we need to declare the statistics in the <code class="highlighter-rouge">SimpleCache</code> object.
They are part of the <code class="highlighter-rouge">Stats</code> namespace. In this case, we’ll make four
statistics. The number of <code class="highlighter-rouge">hits</code> and the number of <code class="highlighter-rouge">misses</code> are just
simple <code class="highlighter-rouge">Scalar</code> counts. We will also add a <code class="highlighter-rouge">missLatency</code> which is a
histogram of the time it takes to satisfy a miss. Finally, we’ll add a
special statistic called a <code class="highlighter-rouge">Formula</code> for the <code class="highlighter-rouge">hitRatio</code> that is a
combination of other statistics (the number of hits and misses).</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">SimpleCache</span> <span class="o">:</span> <span class="k">public</span> <span class="n">MemObject</span>
<span class="p">{</span>
  <span class="nl">private:</span>
    <span class="p">...</span>

    <span class="n">Tick</span> <span class="n">missTime</span><span class="p">;</span> <span class="c1">// To track the miss latency</span>

    <span class="n">Stats</span><span class="o">::</span><span class="n">Scalar</span> <span class="n">hits</span><span class="p">;</span>
    <span class="n">Stats</span><span class="o">::</span><span class="n">Scalar</span> <span class="n">misses</span><span class="p">;</span>
    <span class="n">Stats</span><span class="o">::</span><span class="n">Histogram</span> <span class="n">missLatency</span><span class="p">;</span>
    <span class="n">Stats</span><span class="o">::</span><span class="n">Formula</span> <span class="n">hitRatio</span><span class="p">;</span>

  <span class="nl">public:</span>
    <span class="p">...</span>

    <span class="kt">void</span> <span class="n">regStats</span><span class="p">()</span> <span class="k">override</span><span class="p">;</span>
<span class="p">};</span>
</code></pre></div></div>

<p>Next, we have to define the function to override the <code class="highlighter-rouge">regStats</code> function
so the statistics are registered with gem5’s statistics infrastructure.
Here, for each statistic, we give it a name based on the “parent”
SimObject name and a description. For the histogram statistic, we also
need to initialize it with how many buckets we want in the histogram.
Finally, for the formula, we simply need to write the formula down in
code.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span>
<span class="n">SimpleCache</span><span class="o">::</span><span class="n">regStats</span><span class="p">()</span>
<span class="p">{</span>
    <span class="c1">// If you don't do this you get errors about uninitialized stats.</span>
    <span class="n">MemObject</span><span class="o">::</span><span class="n">regStats</span><span class="p">();</span>

    <span class="n">hits</span><span class="p">.</span><span class="n">name</span><span class="p">(</span><span class="n">name</span><span class="p">()</span> <span class="o">+</span> <span class="s">".hits"</span><span class="p">)</span>
        <span class="p">.</span><span class="n">desc</span><span class="p">(</span><span class="s">"Number of hits"</span><span class="p">)</span>
        <span class="p">;</span>

    <span class="n">misses</span><span class="p">.</span><span class="n">name</span><span class="p">(</span><span class="n">name</span><span class="p">()</span> <span class="o">+</span> <span class="s">".misses"</span><span class="p">)</span>
        <span class="p">.</span><span class="n">desc</span><span class="p">(</span><span class="s">"Number of misses"</span><span class="p">)</span>
        <span class="p">;</span>

    <span class="n">missLatency</span><span class="p">.</span><span class="n">name</span><span class="p">(</span><span class="n">name</span><span class="p">()</span> <span class="o">+</span> <span class="s">".missLatency"</span><span class="p">)</span>
        <span class="p">.</span><span class="n">desc</span><span class="p">(</span><span class="s">"Ticks for misses to the cache"</span><span class="p">)</span>
        <span class="p">.</span><span class="n">init</span><span class="p">(</span><span class="mi">16</span><span class="p">)</span> <span class="c1">// number of buckets</span>
        <span class="p">;</span>

    <span class="n">hitRatio</span><span class="p">.</span><span class="n">name</span><span class="p">(</span><span class="n">name</span><span class="p">()</span> <span class="o">+</span> <span class="s">".hitRatio"</span><span class="p">)</span>
        <span class="p">.</span><span class="n">desc</span><span class="p">(</span><span class="s">"The ratio of hits to the total accesses to the cache"</span><span class="p">)</span>
        <span class="p">;</span>

    <span class="n">hitRatio</span> <span class="o">=</span> <span class="n">hits</span> <span class="o">/</span> <span class="p">(</span><span class="n">hits</span> <span class="o">+</span> <span class="n">misses</span><span class="p">);</span>

<span class="p">}</span>
</code></pre></div></div>

<p>Finally, we need to use update the statistics in our code. In the
<code class="highlighter-rouge">accessTiming</code> class, we can increment the <code class="highlighter-rouge">hits</code> and <code class="highlighter-rouge">misses</code> on a hit
and miss respectively. Additionally, on a miss, we save the current time
so we can measure the latency.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span>
<span class="n">SimpleCache</span><span class="o">::</span><span class="n">accessTiming</span><span class="p">(</span><span class="n">PacketPtr</span> <span class="n">pkt</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">bool</span> <span class="n">hit</span> <span class="o">=</span> <span class="n">accessFunctional</span><span class="p">(</span><span class="n">pkt</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">hit</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">hits</span><span class="o">++</span><span class="p">;</span> <span class="c1">// update stats</span>
        <span class="n">pkt</span><span class="o">-&gt;</span><span class="n">makeResponse</span><span class="p">();</span>
        <span class="n">sendResponse</span><span class="p">(</span><span class="n">pkt</span><span class="p">);</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
        <span class="n">misses</span><span class="o">++</span><span class="p">;</span> <span class="c1">// update stats</span>
        <span class="n">missTime</span> <span class="o">=</span> <span class="n">curTick</span><span class="p">();</span>
        <span class="p">...</span>
</code></pre></div></div>

<p>Then, when we get a response, we need to add the measured latency to our
histogram. For this, we use the <code class="highlighter-rouge">sample</code> function. This adds a single
point to the histogram. This histogram automatically resizes the buckets
to fit the data it receives.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">bool</span>
<span class="n">SimpleCache</span><span class="o">::</span><span class="n">handleResponse</span><span class="p">(</span><span class="n">PacketPtr</span> <span class="n">pkt</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">insert</span><span class="p">(</span><span class="n">pkt</span><span class="p">);</span>

    <span class="n">missLatency</span><span class="p">.</span><span class="n">sample</span><span class="p">(</span><span class="n">curTick</span><span class="p">()</span> <span class="o">-</span> <span class="n">missTime</span><span class="p">);</span>
    <span class="p">...</span>
</code></pre></div></div>

<p>The complete code for the <code class="highlighter-rouge">SimpleCache</code> header file can be downloaded
<a href="/_pages/static/scripts/part2/simplecache/simple_cache.hh">here</a>, and the
complete code for the implementation of the <code class="highlighter-rouge">SimpleCache</code> can be
downloaded
<a href="/_pages/static/scripts/part2/simplecache/simple_cache.cc">here</a>.</p>

<p>Now, if we run the above config file, we can check on the statistics in
the <code class="highlighter-rouge">stats.txt</code> file. For the 1 KB case, we get the following
statistics. 91% of the accesses are hits and the average miss latency is
53334 ticks (or 53 ns).</p>

<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>system.cache.hits                                8431                       # Number of hits
system.cache.misses                               877                       # Number of misses
system.cache.missLatency::samples                 877                       # Ticks for misses to the cache
system.cache.missLatency::mean           53334.093501                       # Ticks for misses to the cache
system.cache.missLatency::gmean          44506.409356                       # Ticks for misses to the cache
system.cache.missLatency::stdev          36749.446469                       # Ticks for misses to the cache
system.cache.missLatency::0-32767                 305     34.78%     34.78% # Ticks for misses to the cache
system.cache.missLatency::32768-65535             365     41.62%     76.40% # Ticks for misses to the cache
system.cache.missLatency::65536-98303             164     18.70%     95.10% # Ticks for misses to the cache
system.cache.missLatency::98304-131071             12      1.37%     96.47% # Ticks for misses to the cache
system.cache.missLatency::131072-163839            17      1.94%     98.40% # Ticks for misses to the cache
system.cache.missLatency::163840-196607             7      0.80%     99.20% # Ticks for misses to the cache
system.cache.missLatency::196608-229375             0      0.00%     99.20% # Ticks for misses to the cache
system.cache.missLatency::229376-262143             0      0.00%     99.20% # Ticks for misses to the cache
system.cache.missLatency::262144-294911             2      0.23%     99.43% # Ticks for misses to the cache
system.cache.missLatency::294912-327679             4      0.46%     99.89% # Ticks for misses to the cache
system.cache.missLatency::327680-360447             1      0.11%    100.00% # Ticks for misses to the cache
system.cache.missLatency::360448-393215             0      0.00%    100.00% # Ticks for misses to the cache
system.cache.missLatency::393216-425983             0      0.00%    100.00% # Ticks for misses to the cache
system.cache.missLatency::425984-458751             0      0.00%    100.00% # Ticks for misses to the cache
system.cache.missLatency::458752-491519             0      0.00%    100.00% # Ticks for misses to the cache
system.cache.missLatency::491520-524287             0      0.00%    100.00% # Ticks for misses to the cache
system.cache.missLatency::total                   877                       # Ticks for misses to the cache
system.cache.hitRatio                        0.905780                       # The ratio of hits to the total access
</code></pre></div></div>

<p>And when using a 128 KB cache, we get a slightly higher hit ratio. It
seems like our cache is working as expected!</p>

<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>system.cache.hits                                8944                       # Number of hits
system.cache.misses                               364                       # Number of misses
system.cache.missLatency::samples                 364                       # Ticks for misses to the cache
system.cache.missLatency::mean           64222.527473                       # Ticks for misses to the cache
system.cache.missLatency::gmean          61837.584812                       # Ticks for misses to the cache
system.cache.missLatency::stdev          27232.443748                       # Ticks for misses to the cache
system.cache.missLatency::0-32767                   0      0.00%      0.00% # Ticks for misses to the cache
system.cache.missLatency::32768-65535             254     69.78%     69.78% # Ticks for misses to the cache
system.cache.missLatency::65536-98303             106     29.12%     98.90% # Ticks for misses to the cache
system.cache.missLatency::98304-131071              0      0.00%     98.90% # Ticks for misses to the cache
system.cache.missLatency::131072-163839             0      0.00%     98.90% # Ticks for misses to the cache
system.cache.missLatency::163840-196607             0      0.00%     98.90% # Ticks for misses to the cache
system.cache.missLatency::196608-229375             0      0.00%     98.90% # Ticks for misses to the cache
system.cache.missLatency::229376-262143             0      0.00%     98.90% # Ticks for misses to the cache
system.cache.missLatency::262144-294911             2      0.55%     99.45% # Ticks for misses to the cache
system.cache.missLatency::294912-327679             1      0.27%     99.73% # Ticks for misses to the cache
system.cache.missLatency::327680-360447             1      0.27%    100.00% # Ticks for misses to the cache
system.cache.missLatency::360448-393215             0      0.00%    100.00% # Ticks for misses to the cache
system.cache.missLatency::393216-425983             0      0.00%    100.00% # Ticks for misses to the cache
system.cache.missLatency::425984-458751             0      0.00%    100.00% # Ticks for misses to the cache
system.cache.missLatency::458752-491519             0      0.00%    100.00% # Ticks for misses to the cache
system.cache.missLatency::491520-524287             0      0.00%    100.00% # Ticks for misses to the cache
system.cache.missLatency::total                   364                       # Ticks for misses to the cache
system.cache.hitRatio                        0.960894                       # The ratio of hits to the total access
</code></pre></div></div>

  <br>

  <!-- RETRIVE PREVIOUS PAGE LINK -->
  
    
  
    
  
    
  
    
  

  <!-- RETRIEVE NEXT PAGE LINK -->
  
    
  
    
  
    
  
    
  


  <div class="navbuttons">
    
      <a href=""><button type="button" class="btn btn-outline-primary">PREVIOUS</button></a>
    

    
      <a href=""><button type="button" class="btn btn-outline-primary">NEXT</button></a>
    
  </div>
</div>

	</main>
	<footer class="page-footer">
	<div class="container">
		<div class="row">

			<div class="col-12 col-sm-4">
				<p>gem5</p>
				<p><a href="/about">About</a></p>
				<p><a href="/publications">Publications</a></p>
				<p><a href="/contributing">Contributing</a></p>
				<p><a href="/governance">Governance</a></p>
			<br></div>

			<div class="col-12 col-sm-4">
				<p>Docs</p>
				<p><a href="/documentation">Documentation</a></p>
				<p><a href="http://gem5.org/Documentation">Old Documentation</a></p>
				<p><a href="https://gem5.googlesource.com/public/gem5">Source</a></p>
			<br></div>

			<div class="col-12 col-sm-4">
				<p>Help</p>
				<p><a href="/search">Search</a></p>
				<p><a href="/mailing_lists">Mailing Lists</a></p>
				<p><a href="https://gem5.googlesource.com/public/gem5-website/+/refs/heads/master/README.md">Website Source</a></p>
			<br></div>

		</div>
	</div>
</footer>


	<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
	<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
	<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
	<script src="https://unpkg.com/commentbox.io/dist/commentBox.min.js"></script>

	<script>
	  // When the user scrolls down 20px from the top of the document, show the button
	  window.onscroll = function() {scrollFunction()};

	  function scrollFunction() {
	      if (document.body.scrollTop > 100 || document.documentElement.scrollTop > 20) {
	          document.getElementById("myBtn").style.display = "block";
	      } else {
	          document.getElementById("myBtn").style.display = "none";
	      }
	  }

	  // When the user clicks on the button, scroll to the top of the document
	  function topFunction() {
	      document.body.scrollTop = 0;
	      document.documentElement.scrollTop = 0;
	  }

		import commentBox from 'commentbox.io';
		// or
		const commentBox = require('commentbox.io');
		// or if using the CDN, it will be available as a global "commentBox" variable.

		commentBox('my-project-id');

	</script>

</body>


</html>
